package com.zbkj.service.service.order.impl;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zbkj.dal.common.exception.CrmebException;
import com.zbkj.dal.dao.OrderRentRecordMapper;
import com.zbkj.dal.entity.order.OrderRentSharedRecord;
import com.zbkj.service.model.dto.order.OrderRentRecordCreateDTO;
import com.zbkj.service.service.order.OrderRentRecordService;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

@Service
public class OrderRentRecordServiceImpl extends ServiceImpl<OrderRentRecordMapper, OrderRentSharedRecord> implements OrderRentRecordService {

    @Autowired
    private OrderRentRecordMapper orderRentRecordMapper;

    @Override
    public String createOrderRentRecord(OrderRentRecordCreateDTO createDTO) {
        OrderRentSharedRecord orderRentSharedRecord = new OrderRentSharedRecord();
        orderRentSharedRecord.setRentCode(IdUtil.getSnowflakeNextIdStr());
        orderRentSharedRecord.setOrderNo(createDTO.getOrderNo());
        orderRentSharedRecord.setOrderDetailId(createDTO.getOrderDetailId());
        orderRentSharedRecord.setUid(createDTO.getUid());
        orderRentSharedRecord.setRentDays(createDTO.getRentDays());
        if (Objects.nonNull(createDTO.getRentStartDate())) {
            CalculateRentDateDTO calculated = this.calculateRentDateDTO(createDTO.getRentStartDate(), orderRentSharedRecord.getRentDays());
            orderRentSharedRecord.setRentStartDate(calculated.getRentStartDate());
            orderRentSharedRecord.setRentEndDate(calculated.getRentEndDate());
            orderRentSharedRecord.setRentReturnDate(calculated.getRentReturnDate());
            orderRentSharedRecord.setExpiredStartDate(calculated.getExpiredStartDate());
            orderRentSharedRecord.setExpiredEndDate(calculated.getExpiredEndDate());
        }
        orderRentSharedRecord.setType(createDTO.getType().name());
        orderRentSharedRecord.setOverdueDays(0);
        orderRentSharedRecord.setStatus(0);
        orderRentSharedRecord.setActive(0);
        orderRentSharedRecord.setCreateTime(LocalDateTime.now());
        orderRentSharedRecord.setUpdateTime(LocalDateTime.now());
        boolean save = super.save(orderRentSharedRecord);
        if (BooleanUtil.isFalse(save)) {
            throw new CrmebException("创建承享记录失败");
        }
        return orderRentSharedRecord.getRentCode();
    }

    @Override
    public Boolean activeOrderRentRecordAfterOrderPay(String order) {
        LambdaQueryWrapper<OrderRentSharedRecord> lambdaQuery = Wrappers.lambdaQuery();
        lambdaQuery.eq(OrderRentSharedRecord::getOrderNo, order);
        lambdaQuery.eq(OrderRentSharedRecord::getType, OrderRentSharedRecord.RentType.INITIAL.name());
        OrderRentSharedRecord orderRentSharedRecord = super.getOne(lambdaQuery);
        orderRentSharedRecord.setActive(1);
        orderRentSharedRecord.setUpdateTime(LocalDateTime.now());
        return super.updateById(orderRentSharedRecord);
    }

    @Override
    public List<OrderRentSharedRecord> getAllOrderRentRecordByOrderNo(String order) {
        LambdaQueryWrapper<OrderRentSharedRecord> lambdaQuery = Wrappers.lambdaQuery();
        lambdaQuery.eq(OrderRentSharedRecord::getOrderNo, order);
        return list(lambdaQuery);
    }

    /**
     * 付款回调中设置 承享记录信息
     *
     * @param rentRecordCode 承享记录编号
     * @param time           开始时间
     * @return 修改是否成功
     */
    @Override
    public Boolean updateOrderRentRecordDate(String rentRecordCode, LocalDateTime time) {
        // 检测是否存在正在承享中的记录
        LambdaQueryWrapper<OrderRentSharedRecord> lambdaQuery = Wrappers.lambdaQuery();
        lambdaQuery.eq(OrderRentSharedRecord::getRentCode, rentRecordCode);
        OrderRentSharedRecord orderRentSharedRecord = super.getOne(lambdaQuery);
        Assert.notNull(orderRentSharedRecord, "承享信息不存在");
        // 如果存在承享中或者承享就绪的记录，则获取到最末结束日期
        LambdaQueryChainWrapper<OrderRentSharedRecord> exits = lambdaQuery();
        lambdaQuery.eq(OrderRentSharedRecord::getOrderNo, orderRentSharedRecord.getOrderNo());
        lambdaQuery.eq(OrderRentSharedRecord::getOrderDetailId, orderRentSharedRecord.getOrderDetailId());
        lambdaQuery.eq(OrderRentSharedRecord::getUid, orderRentSharedRecord.getUid());
        lambdaQuery.in(OrderRentSharedRecord::getStatus, OrderRentSharedRecord.RentRecordStatus.READY.getCode(), OrderRentSharedRecord.RentRecordStatus.RENTING.getCode());
        List<OrderRentSharedRecord> list = super.list(exits);
        // 获取结束的后一天，当作开始时间。 否则就获取支付时间
        LocalDateTime localDateTime = list.stream().map(it -> it.getRentEndDate().toLocalDate().plusDays(1).atStartOfDay()).max(LocalDateTime::compareTo).orElse(time);
        this.updateOrderRentRecord(orderRentSharedRecord, localDateTime);
        return super.updateById(orderRentSharedRecord);
    }

    /**
     * 签收时候记录承享记录信息
     *
     * @param order 承享订单号
     * @return 是否更新成功
     */
    @Override
    public Boolean updateInitialRentOrderStartOnSign(String order) {
        LambdaQueryWrapper<OrderRentSharedRecord> lambdaQuery = Wrappers.lambdaQuery();
        lambdaQuery.eq(OrderRentSharedRecord::getOrderNo, order);
        lambdaQuery.eq(OrderRentSharedRecord::getType, OrderRentSharedRecord.RentType.INITIAL.name());
        OrderRentSharedRecord orderRentSharedRecord = super.getOne(lambdaQuery);
        this.updateOrderRentRecord(orderRentSharedRecord, LocalDateTime.now());
        orderRentSharedRecord.setActive(1);
        return super.updateById(orderRentSharedRecord);
    }

    @Override
    public OrderRentSharedRecord getActiveRentRecordByOrderNo(String order) {
        LambdaQueryWrapper<OrderRentSharedRecord> lambdaQuery = Wrappers.lambdaQuery();
        lambdaQuery.eq(OrderRentSharedRecord::getOrderNo, order);
        lambdaQuery.eq(OrderRentSharedRecord::getActive, 1);
        return orderRentRecordMapper.selectOne(lambdaQuery);
    }

    @Override
    public List<OrderRentSharedRecord> getActiveRentRecordByRentReturnDate(LocalDateTime time) {
        if (Objects.isNull(time)) {
            return Collections.emptyList();
        }
        LambdaQueryWrapper<OrderRentSharedRecord> lambdaQuery = Wrappers.lambdaQuery();
        lambdaQuery.eq(OrderRentSharedRecord::getRentReturnDate, time);
        return list(lambdaQuery);
    }

    @Override
    public List<OrderRentSharedRecord> getHasExpiredActiveRentRecord(LocalDateTime expired) {
        if (Objects.isNull(expired)) {
            return Collections.emptyList();
        }
        LambdaQueryWrapper<OrderRentSharedRecord> lambdaQuery = Wrappers.lambdaQuery();
        lambdaQuery.ge(OrderRentSharedRecord::getExpiredStartDate, expired);
        lambdaQuery.le(OrderRentSharedRecord::getExpiredEndDate, expired);
        lambdaQuery.eq(OrderRentSharedRecord::getActive, 1);
        return list(lambdaQuery);
    }

    @Override
    public List<OrderRentSharedRecord> getHasOverdueActiveRentRecord(LocalDateTime expired) {
        if (Objects.isNull(expired)) {
            return Collections.emptyList();
        }
        LambdaQueryWrapper<OrderRentSharedRecord> lambdaQuery = Wrappers.lambdaQuery();
        lambdaQuery.eq(OrderRentSharedRecord::getExpiredEndDate, expired);
        lambdaQuery.eq(OrderRentSharedRecord::getActive, 1);
        return list(lambdaQuery);
    }

    private void updateOrderRentRecord(OrderRentSharedRecord orderRentSharedRecord, LocalDateTime time) {
        // 检查 当前是否有正常承享的记录，如果存在则设置为承享周期末开始
        CalculateRentDateDTO calculated = this.calculateRentDateDTO(time, orderRentSharedRecord.getRentDays());
        // 开始时间，当前时间开始算
        orderRentSharedRecord.setRentStartDate(calculated.getRentStartDate());
        // 结束时间，当前时间添加 承享 天数
        orderRentSharedRecord.setRentEndDate(calculated.getRentEndDate());
        // 归还时间
        orderRentSharedRecord.setRentReturnDate(calculated.getRentReturnDate());
        // 宽容期开始时间
        orderRentSharedRecord.setExpiredStartDate(calculated.getExpiredStartDate());
        // 宽容期结束时间
        orderRentSharedRecord.setExpiredEndDate(calculated.getExpiredEndDate());
        // 状态更新为承享中
        orderRentSharedRecord.setStatus(1);
        orderRentSharedRecord.setUpdateTime(LocalDateTime.now());
    }

    private CalculateRentDateDTO calculateRentDateDTO(LocalDateTime startTime, Integer rentDays) {
        // 开始时间，当前时间开始算
        LocalDateTime rentStartDate = startTime.toLocalDate().atStartOfDay();
        // 结束时间，当前时间添加 承享 天数
        LocalDateTime rentEndDate = LocalDate.now().plusDays(rentDays).atTime(LocalTime.MAX).truncatedTo(ChronoUnit.SECONDS);
        // 归还时间，结束时间+1天
        LocalDateTime rentReturnDate = rentEndDate.plusDays(1);
        // 宽容期开始时间
        LocalDateTime expiredStartDate = rentReturnDate.plusDays(1).toLocalDate().atStartOfDay();
        // 宽容期结束时间
        LocalDateTime expiredEndDate = expiredStartDate.plusDays(3).toLocalDate().atTime(LocalTime.MAX).truncatedTo(ChronoUnit.SECONDS);
        CalculateRentDateDTO calculateRentDateDTO = new CalculateRentDateDTO();
        calculateRentDateDTO.setRentDays(rentDays);
        calculateRentDateDTO.setRentStartDate(rentStartDate);
        calculateRentDateDTO.setRentEndDate(rentEndDate);
        calculateRentDateDTO.setRentReturnDate(rentReturnDate);
        calculateRentDateDTO.setExpiredStartDate(expiredStartDate);
        calculateRentDateDTO.setExpiredEndDate(expiredEndDate);
        return calculateRentDateDTO;
    }

    @Data
    private static class CalculateRentDateDTO {
        // 承享天数
        private Integer rentDays;
        // 承享开始日期
        private LocalDateTime rentStartDate;
        // 承享结束日期
        private LocalDateTime rentEndDate;
        // 承享归还日期
        private LocalDateTime rentReturnDate;
        // 承享宽容开始时间
        private LocalDateTime expiredStartDate;
        // 承享宽容结束时间
        private LocalDateTime expiredEndDate;
    }
}
